import io
import logging

from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
from rest_framework.permissions import IsAuthenticated
from config.dbs.redis_rev import LOGIN_KEY_TEMPLATE, EXPIRE_TIME
from users.models import UserDetail, Area
from users.serializers import UserSerializer, UserDetailSerializer, UpdatePasswordSerializer, AreaSerializer, ParentSerializer, AddressSerializer
from utils.permission import ActiveUserPermission, wrap_permission, TeacherPermission, RootPermission, update_auto_user, \
    destroy_auto_user, auto_user
from utils.verifyUtil import ImageVerify
from rest_framework.status import HTTP_404_NOT_FOUND,HTTP_400_BAD_REQUEST,HTTP_500_INTERNAL_SERVER_ERROR
from config.fastdfsConfig import FASTDFS_SERVER_DOMAIN
from fdfs_client.client import Fdfs_client, get_tracker_conf
from rest_framework_extensions.cache.mixins import CacheResponseMixin

# 导入日志器
logger = logging.getLogger(__name__)
# tracker server
tracker_path = get_tracker_conf('utils/fastdfs/client.conf')
client = Fdfs_client(tracker_path)


class ImageVerifyView(View):
    """
    图片验证码的视图类

    get
    返回图片验证码
    """
    def get(self, request, uuid):
        """
        返回图片验证码
        :param request: 请求对象
        :param uuid: 客户端唯一识别码
        :return:
        """
        imgVerify = ImageVerify()
        img, code = imgVerify.verify_code()

        # 将图片数据返回给客户端，无需持久化，使用文件流，因为是图片，是字节数据
        img_bytes = io.BytesIO()
        img.save(img_bytes, format='PNG')
        image_bytes = img_bytes.getvalue()  # 图片字节数据

        # 如何保存 uuid:Aw2C key-value 临时数据中，缓存在redis当中
        cache = get_redis_connection(alias='verify_codes')
        cache.set(LOGIN_KEY_TEMPLATE % uuid, code, EXPIRE_TIME)

        return HttpResponse(image_bytes, content_type='image/png')


class UserViewSet(ReadOnlyModelViewSet):
    queryset = User.objects.filter(is_active=1)
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticated]

    def get_serializer(self, *args, **kwargs):
        if self.action == 'password':
            return UpdatePasswordSerializer(*args, **kwargs)
        return self.serializer_class(*args, **kwargs)

    @wrap_permission(TeacherPermission)
    def list(self, request, *args, **kwargs):
        return ReadOnlyModelViewSet.list(self, request, *args, **kwargs)

    @wrap_permission(ActiveUserPermission)
    def retrieve(self, request, *args, **kwargs):
        return ReadOnlyModelViewSet.retrieve(self, request, *args, **kwargs)

    @wrap_permission(ActiveUserPermission)
    def update(self, request, pk):
        # 得到用户 user
        try:
            user = self.get_queryset().get(id=pk)
        except User.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        # 得到用户输入的数据进行反序列化
        user_serializer = self.get_serializer(user, data=request.data)
        # 数据校验
        user_serializer.is_valid(raise_exception = True)
        # 修改user表信息
        user_serializer.save()
        # 判断用户是否传入详情数据
        user_detail = request.data.get('userdetail')  # 获取用户传入的详情数据
        if user_detail:
            # 有，判断用户是否有详情数据，判断数据库中有没有
            if hasattr(user, 'userdetail'):
                # 有，修改
                user_detail_serializer = UserDetailSerializer(user.userdetail, data=user_detail)
            else:
                # 没有，增加
                user_detail['user'] = pk  # 指定用户
                user_detail_serializer = UserDetailSerializer(data=user_detail)
            user_detail_serializer.is_valid(raise_exception=True)
            user_detail_serializer.save()

            user_serializer.data['userdetail'] = UserDetailSerializer(data=user_detail)
        # 返回修改后的数据
        return Response(user_serializer.data)

    @action(methods=['post'], detail=True)
    def avatar(self, request, pk):
        # 获取需要操作的用户
        try:
            user = self.get_queryset().get(id=pk)
        except User.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        # 得到上传的文件数据
        file = request.FILES.get('file')
        # 判断是否是图片数据，文件类型是否是图片
        if not file or file.content_type not in ('image/png', 'image/jpeg', 'image/gif'):
            # 不是图片，返回客户端传入错误数据
            return Response(status=HTTP_400_BAD_REQUEST)
        # 是图片，交给fastdfs，存储到可用的storage服务上
        # 得到文件后缀名，如果没有默认用png
        try:
            images_ext_name = file.name.split('.')[-1]
        except Exception as e:
            logger.info('图片拓展名异常: %s'%e)
            images_ext_name = 'png'
        # 上传图片数据，通过字节流
        try:
            upload_res = client.upload_by_buffer(file.read(), file_ext_name=images_ext_name)
        except Exception as e:
            logger.error('图片上传异常: %s' % e)
            return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            if upload_res.get('Status') != 'Upload successed.':
                logger.warning('图片上传失败')
                return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
            # 得到返回的file_id
            image_name = upload_res.get('Remote file_id').decode()
            image_url = FASTDFS_SERVER_DOMAIN + image_name

            # 判断用户是否有详情表数据
            if hasattr(user, 'userdetail'):
                # 有，修改头像字段，保存图片信息
                user_detail = user.userdetail
                user_detail.avatar = image_url
                user_detail.save()
            else:
                # 没有，创建详情，保存图片信息
                UserDetail.objects.create(avatar=image_url, user=user)
        # 返回头像的图片地址
        return Response({'data': image_url})

    @action(methods=['put'], detail=True)
    def password(self, request, pk):
        # 获取需要操作的用户
        try:
            user = self.get_queryset().get(id=pk)
        except User.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        # 检查原密码是否正确
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        password = request.data['password']  # 得到客户端输入的原密码
        new_password = request.data['new_password']  # 得到用户输入的新密码
        if user.check_password(password):
            # 正确，修改密码
            user.set_password(new_password)
            user.save()
            return Response({'msg': '修改成功'})
        else:
            # 错误，返回提示，原密码错误
            return Response(status=HTTP_400_BAD_REQUEST)


class AreaViewSet(CacheResponseMixin, ModelViewSet):
    queryset = Area.objects.all()
    serializer_class = AreaSerializer

    def get_queryset(self):
        if self.action == 'list':
            return Area.objects.filter(parent=None)
        else:
            return self.queryset

    def get_serializer_class(self):
        if self.action == 'retrieve':
            # 省份
            return ParentSerializer
        else:
            return AreaSerializer

    @wrap_permission(RootPermission)
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permission(RootPermission)
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @wrap_permission(RootPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)


class AddressViewSet(ModelViewSet):
    serializer_class = AddressSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return self.request.user.address_set.filter(is_delete=False)

    @auto_user
    def create(self, request, *args, **kwargs):
        max_count = 10
        if self.get_queryset().count() >= max_count:
            return Response({'detail': f'收货地址数量超出了{max_count}条上限'}, status=HTTP_400_BAD_REQUEST)
        return ModelViewSet.create(self, request, *args, **kwargs)

    @update_auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @destroy_auto_user
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)